﻿#region Header
// Copyright 2007-2011, Jerónimo Milea
// 
// This file is part of NetJsWire.
// 
//     NetJsWire is free software: you can redistribute it and/or modify
//     it under the terms of the GNU General Public License as published by
//     the Free Software Foundation, either version 3 of the License, or
//     (at your option) any later version.
// 
//     NetJsWire is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU General Public License for more details.
// 
//     You should have received a copy of the GNU General Public License
//     along with NetJsWire.  If not, see <http://www.gnu.org/licenses/>.
#endregion

using System;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using NetJsWire.JsonRpcHandler;
using NetJsWire.JsonRpcHandler.Attributes;
using NetJsWire.Widgets.Core;
using NetJsWire.Widgets.Renderers.Core;
using NetJsWire.Widgets.Ui.Form;
using NetJsWire.Widgets.Ui.ToolBar;
using Newtonsoft.Json;
using Formatting = Newtonsoft.Json.Formatting;

namespace NetJsWire.Widgets.Renderers.Form
{
    [ClassName( "NetJsWire.ComboBox" )]
    internal class ComboBox : Widget, IRenderer
    {
        protected string _CHANGESELECTED = string.Empty;// "function( c, r, i ) {{SendToServer(\"{1}\", \"changeSelected\", \"{1}\", r.get('value') );}}";
        protected string _CHANGESELECTED_CLIENT_NAME = "select";

        protected string _SELECTEDINDEXCHANGED = string.Empty;
        private string _clientStore = "'value', 'display'";
        protected string data = string.Empty;
        private CurrencyManager dataManager;

        public ComboBox( object baseObject )
            : base( baseObject )
        {
        }

        #region IRenderer Members

        public override void Render()
        {
            if ( !Rendered )
            {
                var _selIndex = ( ( Ui.Form.ComboBox ) Base ).SelectedItem != null && ( ( Ui.Form.ComboBox ) Base ).SelectedIndex >= 0 ? ( ( Ui.Form.ComboBox ) Base ).SelectedIndex : -1;

                if ( BaseParent is IWidgetContainer )
                {
                    SetAttribute( ControlNode, "isInContainer", true );
                    SetConstructionProperty( "isInContainer", true );
                    //SetConstructionProperty( "sendUpdates", false );
                    if ( IsChildOfType( typeof( Ui.Form.FormPanel ) ) )
                    {
                        SetConstructionProperty( "hiddenName", "__hid__" + InternalID );
                        //SetConstructionProperty( "hiddenId", "__hid__" + InternalID );

                        if ( !string.IsNullOrEmpty( ( Base as IFormField ).FieldLabel ) )
                            SetConstructionProperty( "fieldLabel", ( ( IFormField ) Base ).FieldLabel );
                    }
                }
                else
                {
                    SetStyleProperty( "position", "absolute" );
                    SetConstructionProperty( "parent", ClientParentToRender );
                }

                EnsureParentNodePosition();

                if ( ( ( IComboBox ) Base ).SendUpdates )
                {
                    SetConstructionProperty( "sendUpdates", true );
                }

                //SetStyleProperty( "width", ( ( Ui.Form.ComboBox ) Base ).Width );

                SetConstructionProperty( "tabIndex", ( ( IComboBox ) Base ).TabIndex );
                SetConstructionProperty( "width", ( ( IComboBox ) Base ).Size.Width );
                SetConstructionProperty( "listWidth", ( ( Ui.Form.ComboBox ) Base ).DropDownWidth );
                SetConstructionProperty( "selectOnFocus", ( ( Ui.Form.ComboBox ) Base ).SelectOnFocus );

                if ( ( ( Ui.Form.ComboBox ) Base ).ForceSelection )
                    SetConstructionProperty( "forceSelection", true );
                if ( ( ( Ui.Form.ComboBox ) Base ).TriggerAction != TriggerActionType.query )
                    SetConstructionProperty( "triggerAction", ( ( Ui.Form.ComboBox ) Base ).TriggerAction.ToString() );
                if ( !( ( Ui.Form.ComboBox ) Base ).Editable )
                    SetConstructionProperty( "editable", false );
                if ( ( ( Ui.Form.ComboBox ) Base ).TypeAhead )
                    SetConstructionProperty( "typeAhead", true );

                if ( !string.IsNullOrEmpty( ( ( Ui.Form.ComboBox ) Base ).ItemSelector ) )
                    SetConstructionProperty( "itemSelector", ( ( Ui.Form.ComboBox ) Base ).ItemSelector );

                if ( !string.IsNullOrEmpty( ( ( Ui.Form.ComboBox ) Base ).ColTemplate ) )
                {
                    //SetConstructionProperty("tpl", "cmbTpl");
                    //SetAttribute(ControlNode, "colTpl", ((Ui.Form.ComboBox)Base).ColTemplate);
                    SetConstructionProperty( "tpl", ( ( Ui.Form.ComboBox ) Base ).ColTemplate );
                    //CallCommand("colTpl", ((Ui.Form.ComboBox)Base).ColTemplate);

                    if ( ( ( Ui.Form.ComboBox ) Base ).Columns.Count > 0 )
                    {
                        SetConstructionProperty( "displayField", ( ( Ui.Form.ComboBox ) Base ).DisplayMember );
                        var sbStore = new StringBuilder( "'value'," );
                        foreach ( var col in ( ( Ui.Form.ComboBox ) Base ).Columns )
                        {
                            sbStore.AppendFormat( "'{0}',", col.Field );
                        }
                        if ( sbStore.Length > 0 ) sbStore.Remove( sbStore.Length - 1, 1 );

                        SetConstructionProperty( "fields", string.Format( "[{0}]", sbStore ) );
                    }
                }

                RenderData();

                // We set it here after rendering the data because when we go through the items collection the index gets changed unintentinally...
                ( ( Ui.Form.ComboBox ) Base ).SelectedIndex = _selIndex;
            }

            base.Render();
        }

        #endregion

        //public override string Xtype
        //{
        //    get
        //    {
        //        return "combobox";
        //    }
        //}

        private string BuildColumnTemplate()
        {
            if ( ( ( Ui.Form.ComboBox ) Base ).Columns.Count <= 0 ) return string.Empty;
            var _tplFormat = "<div class='x-combo-list-item' style='height:13px;border:1px solid black;width:{1}px'>{0}</div>";
            var _titleFormat = "<div style='height:15px;'>{0}</div>";
            var _colFormat = "<span style='position: absolute;width: {0}px;left: {1};text-overflow: ellipsis;overflow:hidden;padding:0,2px,0,2px;'>{{{2}}}</span>";
            var tpl = ( ( Ui.Form.ComboBox ) Base ).ColumnHeaders.Split( ',' );
            var cols = "";
            var title = "";
            var colIndex = 0;
            var widthSum = 0;
            var width = 50;
            var _left = 0;
            foreach ( var col in ( ( Ui.Form.ComboBox ) Base ).Columns )
            {
                _left = col.Left;
                if ( _left == 0 && colIndex > 0 )
                {
                    _left = widthSum + ( 4 * colIndex );
                }
                widthSum += col.Width;
                colIndex = ( ( Ui.Form.ComboBox ) Base ).Columns.IndexOf( col );
                cols += string.Format( _colFormat, col.Width, _left, col.Field );
                title += string.Format( _colFormat, col.Width, _left,
                                        ( !string.IsNullOrEmpty( col.Header ) ? col.Header : col.Field ) );
            }
            if ( ( ( Ui.Form.ComboBox ) Base ).DropDownWidth < widthSum ) ( ( Ui.Form.ComboBox ) Base ).DropDownWidth = widthSum + 4;

            ( ( Ui.Form.ComboBox ) Base ).Title = string.Format( _titleFormat,
                                                                 ( title.Length > 0
                                                                       ? title.Replace( "{", "" ).Replace( "}", "" )
                                                                       : "" ) );

            return string.Format( _tplFormat, cols, widthSum + 4 );
        }

        internal void ChangeStore()
        {
            //SetAttribute(ControlNode, "loadData", true);
            //SetAttribute(ControlNode, "changeStore", true);
            if ( ( ( Ui.Form.ComboBox ) Base ).Columns.Count > 0 )
            {
                var sbStore = new StringBuilder( "'value'," );
                foreach ( var col in ( ( Ui.Form.ComboBox ) Base ).Columns )
                {
                    sbStore.AppendFormat( "'{0}',", col.Field );
                }

                if ( sbStore.Length > 0 ) sbStore.Remove( sbStore.Length - 1, 1 );

                //SetAttribute(ControlNode, "store", sbStore.ToString());
                if ( _clientStore != sbStore.ToString() ) AddPrecodeCommand( "setStore", sbStore.ToString() );
                _clientStore = sbStore.ToString();
            }
            else
            {
                if ( _clientStore != "'value', 'display'" )
                {
                    AddPrecodeCommand( "setStore", "'value', 'display'" );
                }
                SetEqualProperty( "displayField", "display" );
                _clientStore = "'value', 'display'";
                //SetAttribute(ControlNode, "store", "'value', 'display'");
            }
        }

        public void RenderData()
        {
            dataManager = null;
            if ( ( ( Ui.Form.ComboBox ) Base ).DataSource != null )
            {
                if ( ( ( Ui.Form.ComboBox ) Base ).BindingContext != null &&
                     ( ( Ui.Form.ComboBox ) Base ).BindingContext[ ( ( Ui.Form.ComboBox ) Base ).DataSource ] != null )
                    dataManager =
                        ( CurrencyManager )
                        ( ( Ui.Form.ComboBox ) Base ).BindingContext[ ( ( Ui.Form.ComboBox ) Base ).DataSource ];
            }
            var ils = ( ( Ui.Form.ComboBox ) Base ).Items;
            if ( ils == null || ils.Count <= 0 )
            {
                //CallCommand( "store.loadData", null );
                //CallCommand( "reset", null );
                WebApplication.Instance.HasChanges = true;
            }
            else if ( ils != null && ils.Count > 0 )
            {
                SetAttribute( ControlNode, "loadData", true );
                var cont = 0;
                foreach ( var o in ils )
                {
                    var chunk =
                        ControlNode[ "data" ].AppendChild(
                            WebApplication.Instance.XmlDocument.CreateNode( XmlNodeType.Element, "chunk", "" ) );

                    if ( ( ( Ui.Form.ComboBox ) Base ).Columns.Count > 0 )
                    {
                        var sbStore = new StringBuilder( "value," );
                        var sbCols = new StringBuilder();
                        foreach ( var col in ( ( Ui.Form.ComboBox ) Base ).Columns )
                        {
                            var o2 = FilterItemOnProperty( o, col.Field );
                            sbCols.AppendFormat( "{0},", JsonConvert.SerializeObject( o2, Formatting.None, new JsonConverter[] { new Newtonsoft.Json.Converters.JavaScriptDateTimeConverter() } ) );

                            sbStore.AppendFormat( "\"{0}\",", col.Field );
                        }
                        if ( sbCols.Length > 0 ) sbCols.Remove( sbCols.Length - 1, 1 );

                        if ( sbStore.Length > 0 ) sbStore.Remove( sbStore.Length - 1, 1 );


                        SetAttribute( ControlNode, "store", sbStore.ToString() );
                        chunk.InnerText = string.Format( "{0},{1}", cont++, sbCols.ToString() );
                    }
                    else
                    {
                        chunk.InnerText = string.Format( "{0},\"{1}\"", cont++, GetItemText( o ) );
                    }
                }
                WebApplication.Instance.HasChanges = true;
            }
        }

        private string GetItemText( object item )
        {
            if ( item == null )
            {
                return string.Empty;
            }
            item = FilterItemOnProperty( item, ( ( Ui.Form.ComboBox ) Base ).DisplayMember );
            if ( item == null )
            {
                return string.Empty;
            }

            return Convert.ToString( item, CultureInfo.CurrentCulture );
        }

        private object FilterItemOnProperty( object item, string field )
        {
            if ( ( item != null ) && ( field.Length > 0 ) )
            {
                try
                {
                    PropertyDescriptor descriptor;
                    if ( dataManager != null )
                    {
                        descriptor = dataManager.GetItemProperties().Find( field, true );
                    }
                    else
                    {
                        descriptor = TypeDescriptor.GetProperties( item ).Find( field, true );
                    }
                    if ( descriptor != null )
                    {
                        item = descriptor.GetValue( item );
                    }
                }
                catch
                {
                }
            }
            return item;
        }
    }
}